﻿using System;

namespace _29_面向对象___泛型
{
    class Program
    {
        const string 分隔符 = "------------------ 分割线 ------------------";
        static void Main(string[] args)
        {
            // ctrl + k+c  :注释语句
            // ctrl+k+u  ：解除注释语句
            //Person<泥巴> 小孩 = new Person<泥巴>("小A", new 泥巴());
            //小孩.和();
            //小孩.切();
            //小孩.煮();
            //Console.WriteLine(分隔符);

            //var 大孩 = new Person<橡皮泥>("大熊", new 橡皮泥());
            //大孩.和();
            //大孩.切();
            //大孩.煮();

            //Console.WriteLine(分隔符);

            //var 老妈 = new Person<面团>("静香", new 面团());
            //老妈.和();
            //老妈.切();
            //老妈.煮();

            Console.WriteLine(分隔符);
            var 坏孩 = new Person<口香糖>("Super熊",new 口香糖("橡胶",666));
            坏孩.和(); // 按下 alt 键 在用鼠标左键撸串,然后就可以统一改东西
            坏孩.切();
            坏孩.煮();

            Console.WriteLine(分隔符);
            var 笨小孩 = new Person<口香糖>("Super笨", null);
            笨小孩.和(); // 按下 alt 键 在用鼠标左键撸串,然后就可以统一改东西
            笨小孩.切();
            笨小孩.煮();

        }

        // CLR  公共语言运行时 （common language runtime）

    }

    // T :泛型参数，约定在 Person 逻辑中使用的 材料 类型。
    // 泛型约束：语法为 [where T：xxx]
    // where :哪儿
    // xxx = 具体的 类类型、结构、接口 ：Person、Book、IEatable
    // xxx = 抽象的 类类型、结构关键字：class 、struct 、(不能用interface 关键字)
    // xxx  =  new() ,代表 泛型T有一个无参构造函数可以调用,只有声明了 new() 才能够 使用 new T();
    //public class Person<T> where T : struct //测试了抽象的结构的约束
    //public class Person<T> where T : class
    //public class Person<T> where T : interface // 接口关键字不能作为约束
    //public class Person<T> where T : ISoft // 约束可以为具体的接口
    // 有了约束，可以访问约束中的类型的成员
    // 可以理解为占位
    public class Person<T> where T : ISoft ,new()
    {
        private T target;
        private string name;
        public Person(string name, T target)
        {
            this.name = name;
            this.target = target??new T(); // ?? :空合并运算符，反问前面的实例是否为空，如果为空则取后面的逻辑
        }
        /// <summary>
        ///  和 huo （面、稀泥、橡皮泥）
        /// </summary>
        /// <param name="target">目标</param>
        public void 和()
        {
            Console.WriteLine($"{this.name} 在和 {typeof(T).Name} - {target.GetType().Name}  - {target}");
            Console.WriteLine($"{this.name} 在和  {target.type} - {target.time} ");
        }
        /// <summary>
        ///  切
        /// </summary>
        public void 切()
        {
            Console.WriteLine($"{this.name} 在切 {typeof(T)} - {target.GetType()}  - {target}");
        }

        public void 煮()
        {
            Console.WriteLine($"{this.name} 在煮 {typeof(T)} - {target.GetType()}  - {target}");
        }
    }

    #region 材料
    public class 口香糖 : ISoft
    {
        public string type { get; set; }
        public  int time { get; set; }
        public 口香糖(string type,int  time) 
        {
            this.type = type;
            this.time = time;
        }
       public 口香糖() 
       {
           this.time = 888;
           this.type = "魔法橡胶";
       }
    }
    
    public class 泥巴
    {
        public string name;
        public override string ToString()
        {
            return "黄色黏土";
        }
    }
    public class 橡皮泥
    {
        public string name;
        public override string ToString()
        {
            return $"{name}海派橡皮泥";
        }
    }
    public class 面团
    {
    }
    public class 水泥
    {
    }

    /// <summary>
    /// 具有柔软特性的东西
    /// </summary>
    // 如果不写修饰符默认 internal
    public interface ISoft //soft 软
    {
        /// <summary>
        /// 材质
        /// </summary>
        string type{ get; set; }
        /// <summary>
        /// 有效期
        /// <br>过了有效期会失去弹性</br>
        /// </summary>
        int time { get; set; }
    }
    #endregion
}
